package com.global.base;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;

/**
 * 
 * @author zly601436
 *
 */
public final class NumberUtil extends Util {
	 
	private NumberUtil(){};
	
	/**
	 * 验证字符串的格式是否符合数字格式（不一定可以转换为数字）
	 * <strong>
	 * <br/><span style="color:red">注意：不能使用本方法验证字符串是否为数字，验证是否为数字时，请参考方法"isCanToNumber"</span>
	 * <br/>合法格式如：123, -123, 1.023, 0.123, -0.1234, 123d, 123D, 123E+12, -123E-12, 0123, 012.12</strong>
	 * @param value
	 * @return true 表示字符串符合数字格式
	 */
	public static boolean isNumberPattern(String value) {		
		errorMessage = "";
		
		if (StringUtils.isNotBlank(value)) {
			Pattern pattern = Pattern.compile(RATIONAL_NUMBER_REGEXP);
			Matcher isNum = pattern.matcher(value);
			if (isNum.matches()) {
				return true;
			}else{
				errorMessage = "字符串不符合数字型字符串的格式";
			}
		} else {
			errorMessage = "字符串为空串";
		}

		return false;
	}	
	
	/**
	 * 验证字符串的格式是否符合正整型数字格式（不一定可以转换为正整数）
	 * <br/><strong>不能使用本方法验证字符串是否为正整数</strong>
	 * <br/><strong>验证字符串是否为正整数时，请参考方法"isCanToInteger"</strong>
	 * @param value
	 * @return true 表示字符串符合正整数格式，合法格式如：123, 0123
	 */
	public static boolean isPositiveIntegerPattern(String value)
	{	
		errorMessage = "";
        
		if(StringUtils.isNotBlank(value)){
			Pattern pattern = Pattern.compile(POSITIVE_INTEGER_REGEXP);
			Matcher isNum = pattern.matcher(value);
			if(isNum.matches()){
				return true;
			}else{
				errorMessage = "字符串不符合正整数的格式";
			}
		}else{
			errorMessage = "字符串为空串";
		}

		return false;
	}
	
	/**
	 * 验证字符串是否可以转换为数字
	 * <br/>合法的字符串如：123, -123, 1.023, 0.123, -0.1234, 123d, 123D, 123E+12, -123E-12, 0123, 012.12
	 * <br/>需要注意的是如果字符串格式正确，但是超出double类型的范围，则返回false
	 * @param value
	 * @return true 表示字符串为数字
	 * @see isDoubleStr
	 */
	public static boolean isCanToNumber(String value)
	{	
		return isCanToDouble(value);
	}
	
	/**
	 * 验证字符串是否可以转换为整型数字
	 * @param value
	 * @return true表示为字符串
	 */
	public static boolean isCanToInteger(String value)
	{	
		errorMessage = "";
        
		if(StringUtils.isNotBlank(value)){
			Pattern pattern = Pattern.compile(INTEGER_REGEXP);
			Matcher isNum = pattern.matcher(value);
			if(isNum.matches())
			{
				try {
					Integer.parseInt(value);
					
					return true;
				} catch (NumberFormatException e) {
					errorMessage = "超出整数范围，应该在【" + Integer.MIN_VALUE + " ~ " + Integer.MAX_VALUE + "】之间";
				}
			}else{
				errorMessage = "字符串不符合整数的格式";
			}
		}

		return false;
	}
	
	/**
	 * 验证浮点数是否可以转换为整型数字
	 * @param value
	 * @return boolean
	 */
	public static boolean isCanToInteger(Double value)
	{	
		errorMessage = "";
        
        try {
        	int intValue = value.intValue();
			if(value==intValue){
				return true;
			}else{
				errorMessage = "给定的Double类型数字超出了Integer类型数字的范围";
			}
		} catch (Exception e) {
			errorMessage = e.getMessage();
		}
		
		return false;
	}
	
	/**
	 * 验证浮点数是否可以转换为整型数字
	 * @param value
	 * @return true表示为字符串
	 */
	public static boolean isCanToInteger(double value)
	{	
		return isCanToInteger(Double.valueOf(value));
	}
	
	/**
	 * 验证长整形数是否可以转换为整型数字
	 * @param value
	 * @return true表示为字符串
	 */
	public static boolean isCanToInteger(Long value)
	{	
		errorMessage = "";
        
        try {
			int intValue = value.intValue();
			if(value==intValue){
				return true;
			}else{
				errorMessage = "给定的Long类型数字超出了Integer类型数字的范围";
			}
		} catch (Exception e) {
			errorMessage = e.getMessage();
		}
		
		return false;
	}
	
	/**
	 * 验证长整形数是否可以转换为整型数字
	 * @param value
	 * @return boolean
	 */
	public static boolean isCanToInteger(long value)
	{			
		return isCanToInteger(Long.valueOf(value));
	}
	
	/**
	 * 验证字符串是否可以转换为长整型数字
	 * @param value
	 * @return boolean
	 */
	public static boolean isCanToLong(String value)
	{	
		errorMessage = "";
        
		if(StringUtils.isNotBlank(value)){
			Pattern pattern = Pattern.compile(INTEGER_REGEXP);
			Matcher isNum = pattern.matcher(value);
			if(isNum.matches()) {
				try {
					Long.parseLong(value);
					
					return true;
				} catch (NumberFormatException e) {
					errorMessage = "超出长整数范围，应该在【" + Long.MIN_VALUE + " ~ " + Long.MAX_VALUE + "】之间";
				}
			}else{
				errorMessage = "字符串不符合长整数的格式";
			}
		}

		return false;
	}
	
	/**
	 * 验证浮点数是否可以转换为长整型数字
	 * @param value
	 * @return boolean
	 */
	public static boolean isCanToLong(Double value)
	{
		errorMessage = "";
        
        try {
        	long longValue = value.longValue();
			if(value==longValue){
				return true;
			}else{
				errorMessage = "给定的Double类型数字超出了Long类型数字的范围";
			}
		} catch (Exception e) {
			errorMessage = e.getMessage();
		}
        
        return false;
	}
	
	/**
	 * 验证浮点数是否可以转换为长整型数字
	 * @param value
	 * @return boolean
	 */
	public static boolean isCanToLong(double value)
	{        
        return isCanToLong(Double.valueOf(value));
	}
	
	/**
	 * 验证字符串是否为浮点型（Float）数字字符串
	 * @param value
	 * @return boolean
	 */
	public static boolean isCanToFloat(String value)
	{	
		errorMessage = "";

		if(StringUtils.isNotBlank(value)){
			Pattern pattern = Pattern.compile(RATIONAL_NUMBER_REGEXP);
			Matcher isNum = pattern.matcher(value);
			if(isNum.matches())
			{
				try {
					Float.parseFloat(value);
					
					return true;
				} catch (NumberFormatException e) {
					errorMessage = "超出浮点数(Float)范围，应该在【" + Float.MIN_VALUE + " ~ " + Float.MAX_VALUE + "】之间";
				}
			}else{
				errorMessage = "字符串不符合浮点数(Float)的格式";
			}
		}

		return false;
	}
	
	/**
	 * 验证字符串是否为浮点型(Double)数字字符串
	 * <br/>合法的浮点型数字如：123，-123，123.123，234d，234D，123E+12等"
	 * <br/> 也可以用来判断是否为数字
	 * @param value
	 * @return true 表示为字符串可以转换为浮点型(double)数字
	 */
	public static boolean isCanToDouble(String value)
	{	
		errorMessage = "";
        
		if(StringUtils.isNotBlank(value)){
			Pattern pattern = Pattern.compile(RATIONAL_NUMBER_REGEXP);
			Matcher isNum = pattern.matcher(value);
			if(isNum.matches()){
				try {
					Double.parseDouble(value);
					
					return true;
				} catch (NumberFormatException e) {
					errorMessage = "超出浮点数(Double)范围，应该在【" + Double.MIN_VALUE + " ~ " + Double.MAX_VALUE + "】之间";
				}
			}else{
				errorMessage = "字符串不符合浮点数(Double)的格式，合法的浮点型数字如：123，-123，123.123，234d，234D，123E+12等";
			}
		}

		return false;
	}
	
	/**
	 * 将十进制数字符串转换为double类型数字
	 * <br/>合法的浮点型（double）数字如：123, -123, 1.023, 123d, 123D, 123E+12, -123E-12"
	 * @param value
	 * @return
	 */
	public static Double getDouble(String value){
		errorMessage = "";
		
		if(isCanToDouble(value)){
			return Double.parseDouble(value);
		}else{
			return null;
		}
	}
	
	/**
	 * 将数字转换成百分比字符串
	 * @param value
	 * @param inLocale 区域码, 如果为空，则取当前区域码
	 * @return String
	 */
	public static String getPercentStr(double value, Locale inLocale){
		errorMessage = "";
		
		NumberFormat percentFormatG = null;
		
		if(inLocale!=null){
			percentFormatG = NumberFormat.getPercentInstance(inLocale);
		}else{
			percentFormatG = NumberFormat.getPercentInstance(Locale.getDefault());
		}
		return percentFormatG.format(value);
	}
	
	/**
	 * 将数字转换成百分比字符串
	 * @param value
	 * @return String
	 */
	public static String getPercentStr(double value){
		return getPercentStr(value, null);
	}
	
	/**
	 * 将数字字符串转换成百分比字符串
	 * @param value
	 * @param inLocale ISO Language Code
	 * @return
	 */
	public static String getPercentStr(String value, Locale inLocale){
		errorMessage = "";
		
		if(isCanToDouble(value)){
			return getPercentStr(getDouble(value), inLocale);
		}else{
			errorMessage = "数字字符串【" + value + "】不合法";
			
			return "";
		}
	}
	
	/**
	 * 将数字转换成百分比字符串
	 * @param value
	 * @param inLocale ISO Language Code
	 * @return
	 */
	public static String getPercentStr(String value){
		errorMessage = "";
		
		return getPercentStr(getDouble(value), Locale.getDefault());
	}
	
	/**
	 * 将数字符串转换成货币字符串
	 * @param value
	 * @param inLocale ISO Language Code
	 * @return
	 */
	public static String getCurrencyStr(double value, Locale inLocale){
		errorMessage = "";
		
		NumberFormat currencyFormatA = null;
		
		if(inLocale!=null){
			currencyFormatA = NumberFormat.getCurrencyInstance(inLocale);
		}else{
			currencyFormatA = NumberFormat.getCurrencyInstance(Locale.getDefault());
		}
		
		return currencyFormatA.format(value);
	}
	
	/**
	 * 将数字转换成货币字符串
	 * @param value
	 * @return
	 */
	public static String getCurrencyStr(double value){		
		return getCurrencyStr(value, Locale.getDefault());
	}
	
	/**
	 * 将数字符串转换成货币字符串
	 * @param value
	 * @param inLocale 区域码, 如果为空，则取默认值的
	 * @return
	 */
	public static String getCurrencyStr(String value, Locale inLocale){
		errorMessage = "";
		
		if(isCanToDouble(value)){
			return getCurrencyStr(getDouble(value), inLocale);
		}else{
			errorMessage = "数字符串【" + value + "】不合法";
			
			return "";
		}
	}
	
	/**
	 * 将数字字符串转换成货币字符串
	 * @param value
	 * @return
	 */
	public static String getCurrencyStr(String value){
		return getCurrencyStr(value, Locale.getDefault());
	}
	
	/**
	 * 格式化数字（包括科学计数法）字符串，保留指定位数的小数（如果精度小于实际位数，则四舍五入）
	 * <br/>异常信息通过方法 getErrorMessage();获得
	 * @param d  需要格式化输出的数字
	 * @param bitNum  小数精度
	 * @return
	 * @see <a href="http://bbs.linuxpk.com/home-space-uid-40688-do-blog-id-16075.html">匹配java double值的正则表达式</a>
	 */
	public static String getNumberFormatStr(Double d, int bitNum) {
		String newStr = "";
		errorMessage = "";
		
		if(d!=null)
		{
			String format = "0 ";
			if (bitNum <= 0) {
				format = "0 ";
			} else {
				format += ". ";
				for (int i = 0; i < bitNum; i++) {
					format += "0 ";
				}
			}
			
			format = (d.doubleValue()<0 && bitNum>0) ? "-" + format : format;
			
			DecimalFormat f = new DecimalFormat(format);			
			newStr = f.format(d.doubleValue());			
			if(StringUtils.contains(newStr, "∞")){
				errorMessage = "值【" + d + "】格式化后已经超出了Double类型数据的范围，则无法格式化输出";
			}
		}
		
		return newStr;
	}
	
	/**
	 * 格式化数字(包括科学计数法)字符串，保留指定位数的小数(如果精度小于实际位数，则四舍五入)
	 * <br/>普通的整数都是合法double型，带上后缀字母d或者D也是double
	 * <br/>异常信息通过方法 getErrorMessage();获得
	 * <br/><span style="color">转换之前，先验证字符串是否为符合要求的数字型字符串</span>
	 * @param numStr  数字字符串
	 * @param bitNum  小数精度
	 * @return
	 * @see <a href="http://bbs.linuxpk.com/home-space-uid-40688-do-blog-id-16075.html">匹配java double值的正则表达式</a>
	 */
	public static String getNumberFormatStr(String numStr, int bitNum) {
		String newStr = "";
		errorMessage = "";
		
		if(StringUtils.isNotBlank(numStr))
		{			
			//浮点数格式，不包括范围
			//普通的整数都是合法double型，带上后缀字母d或者D也是double
			//科学计数法格式，不包括范围
			//CASE_INSENSITIVE：匹配字符时与大小写无关，该标志默认只考虑US ASCII字符。
			//UNICODE_CASE：当与CASE_INSENSITIVE结合时，使用Unicode字母匹配
			Pattern pattern = Pattern.compile(RATIONAL_NUMBER_REGEXP, Pattern.CASE_INSENSITIVE + Pattern.UNICODE_CASE);
			Matcher matcher = pattern.matcher(numStr);
			//字符串格式不符合浮点数格式
			if (!matcher.matches()){
				errorMessage = "值【" + numStr + "】的格式不合法，合法的值如：123, -123, 1.023, 123d, 123D, 123E+12, -123E-12";
			}else{
				if(isCanToDouble(numStr)){
					newStr = getNumberFormatStr(Double.valueOf(numStr), bitNum);					
					if(StringUtils.contains(newStr, "∞")){
						errorMessage = "值【" + numStr + "】格式化后已经超出了Double类型数据的范围，则无法格式化输出";
					}
				}else{
					errorMessage = Util.getErrorMessage();
				}
			}
		}
		
		return newStr;
	}
}
